package colony;

import java.util.ArrayList;
import java.util.List;

import colony.ant.Ant;

public class Colony {

	private Ant[] ants;
	private List<Item> items;
	private Grid grid;

	public static List<Memory> memories;

	public Colony(List<Item> items, Grid grid) {
		super();
		this.items = items;
		this.grid = grid;
		this.ants = new Ant[Engine.numAnts];
		this.memories = new ArrayList<Memory>();

		int antId = 0;
		for (int i = 0; i < this.ants.length; i++) {

			Item item = grid.getFreeItem();

			this.ants[antId] = new Ant(grid, antId, items, item);

			// System.out.println("ant: "+antId+" item: "+item.getId());

			item.setPicked(true);

			antId++;
		}
	}

	public void preAlgorithm() {
		for (int i = 0; i < this.ants.length; i++) {
			Ant ant = ants[i];
			if (ant.getCurrentItem() != null) {
				int id = ant.getCurrentItem().getId();

				if (DistanceMatrix.std[ant.getCurrentItem().getId()] > 1.2 * DistanceMatrix.media) {
					// System.out.println("\nitem: " +
					// ant.getCurrentItem().getId());
					if (!ant.drop()) {
						Position p = Colony.getBestMemory(ant.getCurrentItem());
						if (p != null) {
							ant.setPosition(grid.nexFree(p, p));
						} else {
							ant.setPosition(grid.nextRandom(ant.getPosition(),
									ant.getCurrentItem().getId()));
							Agrupamento.update(ant.getCurrentItem().getId(),
									Agrupamento.getNewClass());
						}
						ant.innerDrop();

					}
				}
			}
		}
	}

	public void algorithm() {
		for (int i = 0; i < this.ants.length; i++) {
			// int id = Engine.rand.nextInt(ants.length);
			Ant ant = ants[i];
			if (ant.getCurrentItem() != null) {

				int id = ant.getCurrentItem().getId();

				if (ant.drop()) {

					boolean picked = false;
					int count = 0;
					while (!picked) {
						count++;
						if (count == items.size()) {
							break;
						}
						Item item = grid.getFreeItem();
						if (item != null) {
							ant.setPosition(item.getPosition());
							picked = ant.pick();
							if (!picked) {
								grid.setFreeItem(item);
							}
						}
					}
				}
			} else {
				int count = 0;
				// boolean picked = ant.pick();
				boolean picked = false;
				while (!picked) {
					// ant.step();
					count++;
					if (count == items.size()) {
						break;
					}
					Item item = grid.getFreeItem();
					if (item != null) {
						ant.setPosition(item.getPosition());
						picked = ant.pick();
						if (!picked) {
							grid.setFreeItem(item);
						}
					}
				}
			}
			ant.step();

		}
	}

	public static int getBestMemoryId(Item item) {
		Memory mbest = null;
		double best = Engine.penalty + 10000;

		for (Memory m : memories) {
			double aux = DistanceMatrix.matrix[item.getId()][m.getItem()
					.getId()];
			if (DistanceMatrix.matrix[item.getId()][m.getItem().getId()] <= best) {
				best = DistanceMatrix.matrix[item.getId()][m.getItem().getId()];
				mbest = m;
			}
		}
		return mbest.getItem().getId();
	}

	public static Position getBestMemory(Item item) {
		for (Memory m : memories) {
			double aux = DistanceMatrix.matrix[item.getId()][m.getItem()
					.getId()];
			if (DistanceMatrix.matrix[item.getId()][m.getItem().getId()] <= 0.12) {
				Agrupamento.updateBasedItem(item.getId(), m.getItem().getId());
				return m.pos.clone();
			}
		}
		return null;
	}

	public static void updateMemory(Position nova, Item item) {
		Memory aux = null;
		double best = Engine.penalty + 10000;
		for (Memory m : memories) {
			if (m.getItem().getId() == item.getId()) {
				// m.setPos(nova.clone());
				Agrupamento.updateBasedItem(item.getId(), m.getItem().getId());
				return;
			}
			double aux2 = DistanceMatrix.matrix[item.getId()][m.getItem()
					.getId()];
			if (DistanceMatrix.matrix[item.getId()][m.getItem().getId()] <= 0.1) {
				// m.item = item;
				// m.pos = nova.clone();
				Agrupamento.updateBasedItem(item.getId(), m.getItem().getId());
				return;
			}

			if (DistanceMatrix.matrix[item.getId()][m.getItem().getId()] < best) {
				aux = m;
				best = DistanceMatrix.matrix[item.getId()][m.getItem().getId()];
			}
		}

		if (aux == null || (aux != null && best > 0.12)) {
			if (memories.size() < 10) {
				memories.add(new Memory(nova.clone(), item));
				Agrupamento.update(item.getId(), Agrupamento.getNewClass());
			} else {
				memories.remove(0);
				memories.add(new Memory(nova.clone(), item));
				Agrupamento.update(item.getId(), Agrupamento.getNewClass());
			}
		} else {
			if (memories.size() < 10) {
				memories.add(new Memory(nova.clone(), item));
				Agrupamento.updateBasedItem(item.getId(), aux.getItem().getId());
			} else {
				memories.remove(0);
				memories.add(new Memory(nova.clone(), item));
				Agrupamento.updateBasedItem(item.getId(), aux.getItem().getId());
			}
		}
	}

	public void finish() {
		for (int i = 0; i < ants.length; i++) {
			ants[i].finish();
		}
	}

}
